/*************************************************************************
    > File Name: ls.c
    > Author: Xing.Dai
    > Mail: Xing.Dai@aliyun.com 
    > Created Time: 2017-05-20 23:33
 ************************************************************************/

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <grp.h>

/**
 * @Synopsis  This function takes a mode value and a char array and puts
 *			  into the char array the file type and the nine letters that 
 *			  correspond to the bits inmode. 
 *	NOTE: It does not code setuid, setgid, and sticky codes.
 */
void mode_to_letters(int mode, char *str)
{
	strcpy(str, "----------");
	
	if(S_ISDIR(mode))
		str[0] = 'd';
	if(S_ISCHR(mode))
		str[0] = 'c';
	if(S_ISBLK(mode))
		str[0] = 'b';
	
	if(mode & S_IRUSR)
		str[1] = 'r';
	if(mode & S_IWUSR)
		str[2] = 'w';
	if(mode & S_IXUSR)
		str[3] = 'x';

	if(mode & S_IRGRP)
		str[4] = 'r';
	if(mode & S_IWGRP)
		str[5] = 'w';
	if(mode & S_IXGRP)
		str[6] = 'x';


	if(mode & S_IROTH)
		str[7] = 'r';
	if(mode & S_IWOTH)
		str[8] = 'w';
	if(mode & S_IXOTH)
		str[9] = 'x';
}

char *uid_to_name(uid_t uid)
{
	struct passwd *pwd_ptr, *getpwuid();
	static char numstr[10];
	
	if((pwd_ptr = getpwuid(uid)) == NULL){
		sprintf(numstr, "%d", uid);
		return NULL;
	} else 
		return pwd_ptr->pw_name;
}

char *gid_to_name(gid_t gid)
{
	struct group *grp_ptr, *getgrgid();
	static char numstr[10];
	
	if((grp_ptr = getgrgid(gid)) == NULL){
		sprintf(numstr, "%d", gid);
		return NULL;
	}else 
		return grp_ptr->gr_name;
}


void show_file_info(char *filename, struct stat *info_p)
{
	char *ctime();
	char modestr[11];

	mode_to_letters(info_p->st_mode, modestr);

	printf("%s", modestr);
	printf("%4d", (int)info_p->st_nlink);
	printf("%-8s", uid_to_name(info_p->st_uid));
	printf("%-8s", gid_to_name(info_p->st_gid));
	printf("%8ld", (long)info_p->st_size);
	printf("%.12s", 4 + ctime(&info_p->st_mtime));
	printf("%s\n", filename);
}



void do_stat(char *filename)
{
	struct stat info;
	
	if(stat(filename, &info) == -1)
		perror(filename);
	else 
		show_file_info(filename, &info);
}

/**
 * @Synopsis  List files in directory called dirname.
 *
 * @Param dirname
 */
void do_ls(char *dirname)
{
	DIR *dir_ptr;
	struct dirent *direntp;

	if((dir_ptr = opendir(dirname)) == NULL){
		fprintf(stderr, "ls: cannot open %s.\n", dirname);
	} else {
		while((direntp = readdir(dir_ptr)) != NULL){
			//printf("%s\n", direntp->d_name);
			do_stat(direntp->d_name);
		}
		closedir(dir_ptr);
	}
}



/**
 * @Synopsis  
 *
 * @Param argc
 * @Param argv
 *
 * @Returns   
 */
int main(int argc, char **argv)
{
	if(argc == 1){
		do_ls(".");
	} else {
		while(--argc){
			printf("%s: \n", *++argv);
			do_ls(*argv);
		}
	}
}



